use std::fmt;
use std::thread::sleep;
use std::time;

// 格式: const 常量名(大写): 类型 = 值 ;
const USER_ID_PREFIX: char = 'U';

// rust 类型分为标量类型和复合类型
// 标量类型指：整形、浮点型、布尔型、字符串型
// 复合类型指：元组、数组
pub fn data_types() {
    // 标量类型

    // 整型
    // 有符号 (i8、i16、i32、i64、i128、isize)
    let num1: i8 = -128; // i8 : -128 - 127
    println!("{}", num1);

    // 无符号 (u8、u16、u32、u64、u128、usize)
    let num2: u8 = 255; // u8 : 0 - 255
    let num3: usize = 1000000; // usize: 根据操作系统架构自动切换32位、64位
    println!("{} {}", num2, num3);

    // 整型字面值
    let num_d = 98_222; // Decimal
    let num_h = 0xff; // Hex
    let num_o = 0o77; // Octal
    let num_b = 0b1111_0000; // Binary
    let num_byte = b'A'; // Byte
    println!("{} {} {} {} {}", num_d, num_h, num_o, num_b, num_byte);

    // 浮点型
    let f_1 = 1.1;
    let f_2: f32 = 1.2;
    println!("{} {}", f_1, f_2);

    // 布尔型

    // 字符类型

    // 复合类型
    // 元组
    let t_1: (i32, f32) = (10, 1.1);
    let t_1y = t_1.0;
    let t_1n = t_1.0;
    // let (t_1n, t_1y) = t_1; // 解构赋值
    println!("{} {}", t_1n, t_1y);

    // 数组
    let a_1 = [1, 2, 3, 4];
    // 通过下标或取值
    println!("a_1[0] : {}", a_1[0]);

    // 遍历
    for i in a_1.iter() {
        println!("{}", i)
    }
}

// rust 变量仅在作用域内生效，默认不可变
pub fn learn_variables() {
    // 格式: let 变量名: 类型 = 值 ;
    // 默认为不可变量
    let x: i32 = 5;
    // 变量默认不可变
    // x = 1; // cannot assign twice to immutable variable
    println!("{}", x);

    // 通过mut 关键字声明可变变量
    let mut y = 10;
    println!("{}", y);
    y = 15;
    println!("{}", y);

    // 常量使用
    println!("常量USER_ID_PREFIX：{}", USER_ID_PREFIX)
}

// 函数由一系列预计和一个可选的表达式构成
// 表达式结尾有分号
// 语句结尾无分号
pub fn sum_function(n1: i32, n2: i32) -> i32 {
    // 默认返回值为()
    // 最后个不以分号结尾为函数返回值
    n1 + n2
}

pub fn demo1_function() {
    let x = 10;
    let y = {
        let x = 20;
        x + 10
        // 大括号结尾自动删除x变量
    };
    println!("y :{}", y);
    println!("x :{}", x);
}

// 流程控制
pub fn control_flow() {
    // if 、else if 、else
    // if 的条件必须是布尔值
    let num = 10;
    if num > 10 {
        println!("num > 10")
    } else if num < 5 {
        println!("num < 5")
    } else {
        println!("10 >= num >= 5 ")
    }

    // let 结合 if使用
    // if 分支的类型必须相同
    let num1 = if num > 10 { num } else { 0 };
    println!("num1 : {}", num1);

    // loop
    let mut loop_num = 0;
    loop {
        loop_num = loop_num + 1;
        println!("loop {}", loop_num);
        if loop_num >= 100 {
            break;
        }
    }
    println!("{}", loop_num);

    // 从 loop 返回
    let loop_rest = loop {
        loop_num = loop_num + 1;
        if loop_num > 200 {
            break loop_num;
        }
    };
    println!("{}", loop_rest);

    // while
    let mut while_num = 100;
    while while_num <= 103 {
        while_num = while_num + 1;
        println!("{}", while_num)
    }

    // for in
    // 遍历元素集合
    let for_list = [1, 2, 3, 4, 5];
    for i in for_list.iter() {
        println!("{}", i)
    }

    // 倒计时示例
    println!("倒计时实例");
    for i in (1..10).rev() {
        sleep(time::Duration::from_millis(500));
        println!("{}", i)
    }
}

// 所有权
// rust 中每个值都有一个被称其为所有者的变量
// 值在任意时刻有且只有一个所有者
// 当所有者离开作用域，这个值就会被丢弃drop
pub fn ownership() {
    // 作用域实例
    {
        let s: &str = "hello1"; // 从此处起，s 是有效的
        println!("{}", s);
    } // 此作用域已结束，s 不再有效

    // 字符串字面量&str 是不可变的，并且是硬编码到代码里的
    // 使用String 类型，来处理不确定的文本情况
    let mut ss = String::from("hello2");
    {
        ss.push_str(" word");
    }
    ss = change(ss);

    println!("{}", ss);
}

// 所有权转移至函数内
// 通过返回值归还所有权
// 继承可变属性
pub fn change(mut ss: String) -> String {
    ss.push_str(" push str");
    ss
}

// 变量与数据交互方式
pub fn var_and_data() {
    // 1. move
    // 当进行Move后，拷贝对象不再可用
    // 编译期避免二次释放BUG
    // Rust 永远也不会自动创建数据的 “深拷贝”。因此，任何 自动 的复制可以被认为对运行时性能影响较小。
    let s3 = String::from("hello3");
    // 所有权变更
    let s4 = s3;
    // println!("{}", s3); // value borrowed here after move
    println!("{}", s4);

    // 2. clone
    let s5 = s4.clone();
    println!("{}", s4);
    println!("{}", s5);

    // 3. borrowing
    let mut s1 = String::from("Hello");
    let len = calculate_length(&s1);
    println!("{} len: {}", s1, len);

    // 4. borrowing mutable
    // 创建可变引用
    // 同一个作用域中不可同时对同一个变量进行可变引用和不可变引用
    // let r1 = &mut s1; // second mutable borrow occurs here
    // 可以在新的作用域中解决此问题
    {
        let r = &mut s1;
        println!("r : {}", r)
    }

    let r1 = &mut s1;
    println!("r1 : {}", r1);

    let r2 = &s1;
    let r3 = &s1;
    // let r4 = &mut s1; // immutable borrow later used here

    println!("r2 : {}", r2);
    println!("r3 : {}", r3);

    // 5. 悬垂指针
    // let s2 = dangle();
}

// fn dangle() -> &String {
//     let s = String::from("hello");
//     &s
// }

// 引用：不会夺取所有权
pub fn calculate_length(_s1: &str) -> usize {
    _s1.len()
}

// 使用切片
pub fn use_slice_demo() {
    // Demo1
    let s1 = String::from("hello world");
    let word_index = first_word(&s1);
    let word_slice = first_word2(&s1); // s1的引用可通过函数的强制转换为&str
    println!("'{}' last word is {}", s1, s1[word_index..].to_string());

    // 清除字符串
    // panic: 不可同时存在可变引用和不可变引用
    // s1.clear();
    // BUG 此时word_index 仍然是零
    // 索引溢出 Panic
    // println!("'{}' first word is {}", s1, s1[word_index..].to_string());
    println!("'{}' first word is {}", s1, word_slice.to_string());
}

// 获取第一个单词索引
fn first_word(s: &String) -> usize {
    // 字符串字节数组
    let bytes = s.as_bytes();

    // 创建数组迭代器
    // enumerate 用于包装迭代器结果，并返回元组（索引，集合元素引用）
    // 解构赋值
    for (i, &item) in bytes.iter().enumerate() {
        // 如果为空格返回当前索引
        if item == b' ' {
            return i;
        }
    }
    bytes.len()
}

// 获取第一个单词切片
// slice 字面值为&str, 不可变引用
fn first_word2(s: &str) -> &str {
    // 字符串字节数组
    let bytes = s.as_bytes();

    // 创建数组迭代器
    // enumerate 用于包装迭代器结果，并返回元组（索引，集合元素引用）
    // 解构赋值
    for (i, &item) in bytes.iter().enumerate() {
        // 如果为空格返回当前索引
        if item == b' ' {
            return &s[0..i];
        }
    }
    &s[..]
}

// 定义结构体
struct User {
    name: String,
    age: isize,
    active: bool,
}

// 定义元组结构体
// struct Color(i32, i32, i32);

// 定义类单元结构体
// struct AlwaysEqual;

impl User {
    fn new(name: String, age: isize, active: bool) -> Self {
        Self { name, age, active }
    }

    /// Set the user's active.
    fn set_active(&mut self, active: bool) {
        self.active = active;
    }

    // Clone this struct
    pub(crate) fn clone(&self) -> User {
        User {
            name: self.name.clone(),
            age: self.age.clone(),
            active: self.active.clone(),
        }
    }
}

// User结构体构造方法
fn build_user(name: String, age: isize) -> User {
    User {
        name: name,
        age: age,
        active: true,
    }
}

// 使用结构体
pub fn use_struct() {
    // 实例化结构体
    let mut u1 = User {
        name: String::from("John"),
        age: 30,
        active: true,
    };

    u1.set_active(false);

    // 通过构造函数创建
    let u2 = build_user(String::from("Tony"), u1.age);

    // 从其他实例创建
    // filed copy
    let u3 = User {
        name: String::from("Tom"),
        ..u2
    };

    // 移动和借用同样适用于结构体
    let u4 = u3;
    let u5 = u4.clone(); // 手动实现clone
    let u6 = User { ..u5 };
    println!("{}", u4.age);
    println!("{}", u5.age);
    println!("{}", u6.age);

    // 实例化元组结构体
    // let bg_color = Color(0, 0, 255);
    // println!(
    //     "background color is {} {} {}",
    //     bg_color.0, bg_color.1, bg_color.2
    // );

    // 实例化类单元结构体
    // let subject = AlwaysEqual;

    //
    let u7 = User::new(String::from("Daived"), 10, true);
    println!("{}", u7.name);
}

#[derive(Debug)]
struct Rect {
    width: u32,
    height: u32,
}

impl Rect {
    fn area(&self) -> u32 {
        self.width * self.height
    }
    fn check_width(&self) -> bool {
        self.width > 0
    }

    /// Get a reference to the rect's width.
    fn width(&self) -> u32 {
        self.width
    }

    fn can_hold(&self, other: &Rect) -> bool {
        self.width >= other.width && self.height >= other.height
    }
}

// 结构体示例
pub fn use_struct_demo() {
    let mut rect1 = Rect {
        width: 20,
        height: 30,
    };

    // format print struct
    // add Debug trait for  struct
    println!("rect1 is {:?}", rect1);
    println!("rect1 is {:#?}", rect1);

    // Debug
    rect1 = dbg!(rect1);
    println!("rect1 area is {}", rect1.area());

    // Check
    if rect1.check_width() {
        println!("rect1 check success {}", dbg!(rect1.width()));
    }

    let rect2 = Rect {
        width: 10,
        height: 30,
    };
    let rect3 = Rect {
        width: 30,
        height: 40,
    };
    println!("rect1 can_hold rect2 {}", rect1.can_hold(&rect2));
    println!("rect1 can_hold rect3 {}", rect1.can_hold(&rect3));
}

// 枚举类型
#[derive(Debug)]
enum ActionType {
    SLAP(String),
    TOUCH(String),
}

#[derive(Debug)]
struct Record {
    u_id: String,            // 用户ID
    action_type: ActionType, // 动作类型
    timestamp: usize,        // 时间戳
}

impl Record {
    fn save(&self) {
        println!("{:?} save success", self)
    }

    fn check(&self) -> bool {
        // 匹配是穷尽的，必须枚举到最后的可能性来使代码可用
        match self.action_type {
            ActionType::SLAP(_) => true,
            ActionType::TOUCH(_) => {
                println!("don't use touch!");
                false
            }
        }
    }
}

// 通过泛型定义枚举类型
// enum Option<T> {
//     Some(T),
// }

pub fn use_enum() {
    let rc = Record {
        u_id: "00001".to_string(),
        action_type: ActionType::SLAP("slap".to_string()),
        timestamp: 111111,
    };

    rc.save();

    // let o = Some(1);
}

pub fn use_match() {
    let rc = Record {
        u_id: "11111".to_string(),
        action_type: ActionType::TOUCH("hit me".to_string()),
        timestamp: 222222,
    };
    println!("check {}", rc.check());
}

#[derive(Debug)]
enum ColorRed {
    Light,
    Crimson,
}

#[derive(Debug)]
enum Color {
    Red(ColorRed),
    Green,
}

pub fn use_enum_branch() {
    let c = Color::Red(ColorRed::Light);
    match c {
        Color::Red(branch) => {
            println!("c branch is {:?}", branch)
        }
        Color::Green => {}
    }

    let c1 = Color::Red(ColorRed::Crimson);
    println!("c1 is {:?}", c1);

    let c2 = Color::Green;
    println!("c2 is {:?}", c2);
}

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        Some(i) => Some(i + 1),
        None => None,
    }
}

pub fn use_match_option() {
    let o = Option::Some(10);
    let o1 = plus_one(o);
    println!("o1 is {:?}", o1);
}

// match 的通配符模式
pub fn use_match_wildcard() {
    let num = 10;
    match num {
        10 => {
            println!("yes")
        }
        _ => {
            println!("not found")
        }
    }
}

// 使用if let 可简写match，不必遵循穷尽原则
pub fn use_if_let() {
    let o = Some(10);
    if let Some(10) = o {
        println!("{:?} eq Option::Some(10)", o);
    } else {
    }
}

// 模块方法拥有私有性
mod front_of_house {
    pub mod hosting {
        pub fn add_wait_list() {
            println!("from front_of_house")
        }
    }
}
fn add_wait_list() {
    println!("from base")
}

pub fn use_package_mod() {
    front_of_house::hosting::add_wait_list();
    add_wait_list();
}
